#include "U2ControllerManager.h"

#include "U2LogManager.h"
#include "U2Root.h"


U2EG_NAMESPACE_USING


//-----------------------------------------------------------------------
template<> ControllerManager* U2Singleton<ControllerManager>::s_pSingleton = 0;
ControllerManager* ControllerManager::getSingletonPtr(void)
{
    return s_pSingleton;
}
ControllerManager& ControllerManager::getSingleton(void)
{  
    assert( s_pSingleton );  return ( *s_pSingleton );  
}
//-----------------------------------------------------------------------
ControllerManager::ControllerManager()
: mFrameTimeController(U2_NEW FrameTimeControllerValue())
, mPassthroughFunction(U2_NEW PassthroughControllerFunction())
, mLastFrameNumber(0)
{

}
//-----------------------------------------------------------------------
ControllerManager::~ControllerManager()
{
    clearControllers();
}
//-----------------------------------------------------------------------
Controller<u2real>* ControllerManager::createController(
    const ControllerValueRealPtr& src, const ControllerValueRealPtr& dest,
    const ControllerFunctionRealPtr& func)
{
    Controller<u2real>* c = U2_NEW Controller<u2real>(src, dest, func);

    mControllers.insert(c);
    return c;
}
//-----------------------------------------------------------------------
Controller<u2real>* ControllerManager::createFrameTimePassthroughController(
    const ControllerValueRealPtr& dest)
{
    return createController(getFrameTimeSource(), dest, getPassthroughControllerFunction());
}
//-----------------------------------------------------------------------
void ControllerManager::updateAllControllers(void)
{
    // Only update once per frame
    unsigned long thisFrameNumber = U2Root::getSingleton().getNextFrameNumber();
    if (thisFrameNumber != mLastFrameNumber)
    {
        ControllerList::const_iterator ci;
        for (ci = mControllers.begin(); ci != mControllers.end(); ++ci)
        {
            (*ci)->update();
        }
        mLastFrameNumber = thisFrameNumber;
    }
}
//-----------------------------------------------------------------------
void ControllerManager::clearControllers(void)
{
    ControllerList::iterator ci;
    for (ci = mControllers.begin(); ci != mControllers.end(); ++ci)
    {
        U2_DELETE *ci;
    }
    mControllers.clear();
}
//-----------------------------------------------------------------------
const ControllerValueRealPtr& ControllerManager::getFrameTimeSource(void) const
{
    return mFrameTimeController;
}
//-----------------------------------------------------------------------
const ControllerFunctionRealPtr& ControllerManager::getPassthroughControllerFunction(void) const
{
	return mPassthroughFunction;
}
//-----------------------------------------------------------------------
Controller<u2real>* ControllerManager::createTextureAnimator(TextureUnitState* layer, u2real sequenceTime)
{
    U2SharedPtr< ControllerValue<u2real> > texVal(U2_NEW TextureFrameControllerValue(layer));
    U2SharedPtr< ControllerFunction<u2real> > animFunc(U2_NEW AnimationControllerFunction(sequenceTime));

    return createController(mFrameTimeController, texVal, animFunc);
}
//-----------------------------------------------------------------------
Controller<u2real>* ControllerManager::createTextureUVScroller(TextureUnitState* layer, u2real speed)
{
	Controller<u2real>* ret = 0;

	if (speed != 0)
    {
		U2SharedPtr< ControllerValue<u2real> > val;
		U2SharedPtr< ControllerFunction<u2real> > func;

		// We do both scrolls with a single controller
		val.bind(U2_NEW TexCoordModifierControllerValue(layer, true, true));
		// Create function: use -speed since we're altering texture coords so they have reverse effect
        func.bind(U2_NEW ScaleControllerFunction(-speed, true));
        ret = createController(mFrameTimeController, val, func);
	}

	return ret;
}
//-----------------------------------------------------------------------
Controller<u2real>* ControllerManager::createTextureUScroller(TextureUnitState* layer, u2real uSpeed)
{
    Controller<u2real>* ret = 0;

    if (uSpeed != 0)
    {
		U2SharedPtr< ControllerValue<u2real> > uVal;
		U2SharedPtr< ControllerFunction<u2real> > uFunc;

        uVal.bind(U2_NEW TexCoordModifierControllerValue(layer, true));
        // Create function: use -speed since we're altering texture coords so they have reverse effect
        uFunc.bind(U2_NEW ScaleControllerFunction(-uSpeed, true));
        ret = createController(mFrameTimeController, uVal, uFunc);
    }

    return ret;
}
//-----------------------------------------------------------------------
Controller<u2real>* ControllerManager::createTextureVScroller(TextureUnitState* layer, u2real vSpeed)
{
	Controller<u2real>* ret = 0;

	if (vSpeed != 0)
    {
		U2SharedPtr< ControllerValue<u2real> > vVal;
		U2SharedPtr< ControllerFunction<u2real> > vFunc;

        // Set up a second controller for v scroll
        vVal.bind(U2_NEW TexCoordModifierControllerValue(layer, false, true));
        // Create function: use -speed since we're altering texture coords so they have reverse effect
        vFunc.bind(U2_NEW ScaleControllerFunction(-vSpeed, true));
        ret = createController(mFrameTimeController, vVal, vFunc);
    }

    return ret;
}
//-----------------------------------------------------------------------
Controller<u2real>* ControllerManager::createTextureRotater(TextureUnitState* layer, u2real speed)
{
    U2SharedPtr< ControllerValue<u2real> > val;
    U2SharedPtr< ControllerFunction<u2real> > func;

    // Target value is texture coord rotation
    val.bind(U2_NEW TexCoordModifierControllerValue(layer, false, false, false, false, true));
    // Function is simple scale (seconds * speed)
    // Use -speed since altering texture coords has the reverse visible effect
    func.bind(U2_NEW ScaleControllerFunction(-speed, true));

    return createController(mFrameTimeController, val, func);
}
//-----------------------------------------------------------------------
Controller<u2real>* ControllerManager::createTextureWaveTransformer(TextureUnitState* layer,
    TextureUnitState::TextureTransformType ttype, WaveformType waveType, u2real base, u2real frequency, u2real phase, u2real amplitude)
{
    U2SharedPtr< ControllerValue<u2real> > val;
    U2SharedPtr< ControllerFunction<u2real> > func;

    switch (ttype)
    {
    case TextureUnitState::TT_TRANSLATE_U:
        // Target value is a u scroll
        val.bind(U2_NEW TexCoordModifierControllerValue(layer, true));
        break;
    case TextureUnitState::TT_TRANSLATE_V:
        // Target value is a v scroll
        val.bind(U2_NEW TexCoordModifierControllerValue(layer, false, true));
        break;
    case TextureUnitState::TT_SCALE_U:
        // Target value is a u scale
        val.bind(U2_NEW TexCoordModifierControllerValue(layer, false, false, true));
        break;
    case TextureUnitState::TT_SCALE_V:
        // Target value is a v scale
        val.bind(U2_NEW TexCoordModifierControllerValue(layer, false, false, false, true));
        break;
    case TextureUnitState::TT_ROTATE:
        // Target value is texture coord rotation
        val.bind(U2_NEW TexCoordModifierControllerValue(layer, false, false, false, false, true));
        break;
    }
    // Create new wave function for alterations
    func.bind(U2_NEW WaveformControllerFunction(waveType, base, frequency, phase, amplitude, true));

    return createController(mFrameTimeController, val, func);
}
//-----------------------------------------------------------------------
/**********************@@@@@@@@@@@@@@@@@@@@@
Controller<u2real>* ControllerManager::createGpuProgramTimerParam(
    GpuProgramParametersSharedPtr params, size_t paramIndex, u2real timeFactor)
{
    U2SharedPtr< ControllerValue<u2real> > val;
    U2SharedPtr< ControllerFunction<u2real> > func;

    val.bind(U2_NEW FloatGpuParameterControllerValue(params, paramIndex));
    func.bind(U2_NEW ScaleControllerFunction(timeFactor, true));

    return createController(mFrameTimeController, val, func);
}
*/
//-----------------------------------------------------------------------
void ControllerManager::destroyController(Controller<u2real>* controller)
{
    ControllerList::iterator i = mControllers.find(controller);
    if (i != mControllers.end())
    {
        mControllers.erase(i);
        U2_DELETE controller;
    }
}
//-----------------------------------------------------------------------
u2real ControllerManager::getTimeFactor(void) const {
	return static_cast<const FrameTimeControllerValue*>(mFrameTimeController.get())->getTimeFactor();
}
//-----------------------------------------------------------------------
void ControllerManager::setTimeFactor(u2real tf) {
	static_cast<FrameTimeControllerValue*>(mFrameTimeController.getPointer())->setTimeFactor(tf);
}
//-----------------------------------------------------------------------
u2real ControllerManager::getFrameDelay(void) const {
	return static_cast<const FrameTimeControllerValue*>(mFrameTimeController.get())->getFrameDelay();
}
//-----------------------------------------------------------------------
void ControllerManager::setFrameDelay(u2real fd) {
	static_cast<FrameTimeControllerValue*>(mFrameTimeController.getPointer())->setFrameDelay(fd);
}
//-----------------------------------------------------------------------
u2real ControllerManager::getElapsedTime(void) const
{
	return static_cast<const FrameTimeControllerValue*>(mFrameTimeController.get())->getElapsedTime();
}
//-----------------------------------------------------------------------
void ControllerManager::setElapsedTime(u2real elapsedTime)
{
	static_cast<FrameTimeControllerValue*>(mFrameTimeController.get())->setElapsedTime(elapsedTime);
}